package com.hy.mvc.biz.excel.builder.impl;

import com.google.common.collect.Lists;
import com.hy.mvc.biz.excel.anotation.CellConvert;
import com.hy.mvc.biz.excel.builder.AbstractSheetBuilder;
import com.hy.mvc.biz.excel.builder.ExcelBuilder;
import com.hy.mvc.biz.excel.enums.CellType;
import com.hy.mvc.biz.excel.enums.ExportMode;
import com.hy.mvc.biz.excel.model.SimpleExcelModel;
import com.hy.mvc.biz.excption.FileUploadException;
import com.hy.mvc.biz.utils.MathUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;

/**
 * Created by Booker on 2017/7/3.
 */
@Component("excelBuilderImpl")
public class ExcelBuilderImpl implements ExcelBuilder {
    private static Log log = LogFactory.getLog(ExcelBuilderImpl.class);

    private static final int DEFAULT_TOTAL_SHEET = 1;

    @Override
    public HSSFWorkbook buildExport(HSSFWorkbook workbook, AbstractSheetBuilder sheetBuilder, List<?> exportList) {
        SimpleExcelModel excelModel = sheetBuilder.getExcelModel();

        if (excelModel == null) {
            log.error("SheetBuilder初始化时未设置excelModel属性", new NullPointerException());
            return workbook;
        }

        int totalSheet = DEFAULT_TOTAL_SHEET;

        if (excelModel.getExportMode() == ExportMode.MANYSHEET) {
            totalSheet = MathUtils.ceil(exportList.size(), excelModel.getSheetSize());
        }

        for (int i = 1; i <= totalSheet; i++) {
            String sheetName = excelModel.getFileName();
            if (totalSheet > DEFAULT_TOTAL_SHEET) {
                sheetName = new StringBuffer().append(sheetName).append(i).toString();
            }

            HSSFSheet workSheet = workbook.createSheet(sheetName);

            int start = (i - 1) * excelModel.getSheetSize();
            int end = i * excelModel.getSheetSize();
            if (totalSheet == i) {
                end = exportList.size();
            }

            workSheet = sheetBuilder.buildSheet(workSheet, exportList.subList(start, end));
        }

        return workbook;
    }

    @Override
    public <T> List<T> buildImport(InputStream inputStream, Class<T> clazz,
                                   int startRowIndex) {
        Workbook workbook = null;

        try {
            workbook = new HSSFWorkbook(inputStream);
        } catch (IOException e) {
            log.error("打开Excel文件的输入流时出错!", e);
            throw new FileUploadException("未能正确打开Excel文件!", e);
        }

        int sheetNum = workbook.getNumberOfSheets();
        List<T> excelConvertEntities = Lists.newLinkedList();

        for (int i = 0; i < sheetNum; i++) {
            Sheet sheet = workbook.getSheetAt(i);
            int rowNum = sheet.getLastRowNum();

            for (int j = startRowIndex; j <= rowNum; j++) {
                Row row = sheet.getRow(j);
                excelConvertEntities.add(convertToEntity(row, clazz));
            }
        }

        return excelConvertEntities;
    }

    private <T> T convertToEntity(Row row, Class<T> clazz) {
        T t = null;
        try {
            t = clazz.newInstance();
        } catch (Exception e) {
            log.error("获取Excel的导出对象时出错!", e);
        }

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(CellConvert.class)) {
                CellConvert cellConvert = field.getAnnotation(CellConvert.class);

                int colum = cellConvert.colum();
                Cell cell = row.getCell(colum);

                field.setAccessible(true);
                try {
                    CellType cellType = getDeclareCellType(cell.getCellType());
                    if (cellType != null) {
                        Object value = cellConvert.dataType().convertDataType(cellType.convertCell(cell));
                        field.set(t, value);
                    } else {
                        log.error("导入Excel过程中获取cellType错误!cellType为" + cell.getCellType());
                    }
                } catch (Exception e) {
                    log.error("导入Excel过程中给实体属性赋值时出错!", e);
                } finally {
                    field.setAccessible(false);
                }
            }
        }

        return t;
    }

    private CellType getDeclareCellType(int type) {
        for (CellType cellType : CellType.values()) {
            if (cellType.getType() == type) {
                return cellType;
            }
        }
        return null;
    }
}
